add privileged (dom0) kernel feature indication
authorJan Beulich <jbeulich@novell.com>
Sat, 23 Jul 2011 07:49:15 +0000 (08:49 +0100)
committerJan Beulich <jbeulich@novell.com>
Sat, 23 Jul 2011 07:49:15 +0000 (08:49 +0100)
With our switching away from supporting 32-bit Dom0 operation, users
complained that attempts (perhaps due to lack of knowledge of that
change) to boot the no longer privileged kernel in Dom0 resulted in
apparently silent failure. To make the mismatch explicit and visible,
add dom0 feature flag that the kernel can set to indicate operation as
dom0 is supported.

Due to the way elf_xen_parse_features() worked up to now (getting
fixed here), adding features indications to the old, string based ELF
note would make the respective kernel unusable on older hypervisors.
For that reason, a new ELF Note is being introduced that allows
specifying supported features as a bit array instead (with features
unknown to the hypervisor simply ignored, as now also done by
elf_xen_parse_features(), whereas here unknown kernel-required
features still keep the kernel [and hence VM] from booting).

Introduce and use elf_note_numeric_array() to be forward
compatible (or else an old hypervisor wouldn't be able to parse kernel
specified features occupying more than 64 bits - thanks, Ian!).

Signed-off-by: Jan Beulich <jbeulich@novell.com>
tools/libxc/xc_dom_elfloader.c
xen/arch/ia64/xen/domain.c
xen/arch/x86/domain_build.c
xen/common/kernel.c
xen/common/libelf/libelf-dominfo.c
xen/common/libelf/libelf-tools.c
xen/include/public/elfnote.h
xen/include/public/features.h
xen/include/xen/libelf.h

index 9114bfb333a8a7da97129b46eaf0d74d80ef77cd..906e3a2f07b7878e008f8bdccb391e1728480985 100644 (file)
@@ -286,6 +286,13 @@ static int xc_dom_parse_elf_kernel(struct xc_dom_image *dom)
     if ( (rc = elf_xen_parse(elf, &dom->parms)) != 0 )
         return rc;
 
+    if ( elf_xen_feature_get(XENFEAT_dom0, dom->parms.f_required) )
+    {
+        xc_dom_panic(dom->xch, XC_INVALID_KERNEL, "%s: Kernel does not"
+                     " support unprivileged (DomU) operation", __FUNCTION__);
+        return -EINVAL;
+    }
+
     /* find kernel segment */
     dom->kernel_seg.vstart = dom->parms.virt_kstart;
     dom->kernel_seg.vend   = dom->parms.virt_kend;
index 271a744e872736358a5bb90ec143756eb28e4eeb..957c288710c8e06db84d9915272375eeafe0674e 100644 (file)
@@ -2164,6 +2164,13 @@ int __init construct_dom0(struct domain *d,
                return -1;
        }
 
+       if (parms.elf_notes[XEN_ELFNOTE_FEATURES].type != XEN_ENT_NONE &&
+           !test_bit(XENFEAT_dom0, parms.f_supported))
+       {
+               printk("Kernel does not support Dom0 operation\n");
+               return -1;
+       }
+
        p_start = parms.virt_base;
        pkern_start = parms.virt_kstart;
        pkern_end = parms.virt_kend;
index cbb92699f764a2c3228a6e7238a4c4ea980259d7..8d58291c33c2b116b3a59b32e95cf54788f74d4d 100644 (file)
@@ -415,6 +415,13 @@ int __init construct_dom0(
         return -EINVAL;
     }
 
+    if ( parms.elf_notes[XEN_ELFNOTE_FEATURES].type != XEN_ENT_NONE &&
+         !test_bit(XENFEAT_dom0, parms.f_supported) )
+    {
+        printk("Kernel does not support Dom0 operation\n");
+        return -EINVAL;
+    }
+
 #if defined(__x86_64__)
     if ( compat32 )
     {
index 5558dc0712ab81eb1a65e6251e519c90567e05cb..7decc1d70d42dfcb7cf63871ca93d7465dfa798b 100644 (file)
@@ -287,6 +287,8 @@ DO(xen_version)(int cmd, XEN_GUEST_HANDLE(void) arg)
                     (1U << XENFEAT_auto_translated_physmap);
             if ( supervisor_mode_kernel )
                 fi.submap |= 1U << XENFEAT_supervisor_mode_kernel;
+            if ( current->domain == dom0 )
+                fi.submap |= 1U << XENFEAT_dom0;
 #ifdef CONFIG_X86
             if ( !is_hvm_vcpu(current) )
                 fi.submap |= (1U << XENFEAT_mmu_pt_update_preserve_ad) |
index 57ca26088b26f3686b3c9e47132829a96db70d9a..c569a4893a09c3777ce28ae5c204524a7584d04c 100644 (file)
@@ -26,7 +26,8 @@ static const char *const elf_xen_feature_names[] = {
     [XENFEAT_writable_descriptor_tables] = "writable_descriptor_tables",
     [XENFEAT_auto_translated_physmap] = "auto_translated_physmap",
     [XENFEAT_supervisor_mode_kernel] = "supervisor_mode_kernel",
-    [XENFEAT_pae_pgdir_above_4gb] = "pae_pgdir_above_4gb"
+    [XENFEAT_pae_pgdir_above_4gb] = "pae_pgdir_above_4gb",
+    [XENFEAT_dom0] = "dom0"
 };
 static const int elf_xen_features =
 sizeof(elf_xen_feature_names) / sizeof(elf_xen_feature_names[0]);
@@ -83,7 +84,7 @@ int elf_xen_parse_features(const char *features,
                 }
             }
         }
-        if ( i == elf_xen_features )
+        if ( i == elf_xen_features && required && feature[0] == '!' )
             return -1;
     }
 
@@ -114,6 +115,7 @@ int elf_xen_parse_note(struct elf_binary *elf,
         [XEN_ELFNOTE_LOADER] = { "LOADER", 1},
         [XEN_ELFNOTE_PAE_MODE] = { "PAE_MODE", 1},
         [XEN_ELFNOTE_FEATURES] = { "FEATURES", 1},
+        [XEN_ELFNOTE_SUPPORTED_FEATURES] = { "SUPPORTED_FEATURES", 0},
         [XEN_ELFNOTE_BSD_SYMTAB] = { "BSD_SYMTAB", 1},
         [XEN_ELFNOTE_SUSPEND_CANCEL] = { "SUSPEND_CANCEL", 0 },
         [XEN_ELFNOTE_MOD_START_PFN] = { "MOD_START_PFN", 0 },
@@ -122,6 +124,7 @@ int elf_xen_parse_note(struct elf_binary *elf,
 
     const char *str = NULL;
     uint64_t val = 0;
+    unsigned int i;
     int type = elf_uval(elf, note, type);
 
     if ( (type >= sizeof(note_desc) / sizeof(note_desc[0])) ||
@@ -200,6 +203,12 @@ int elf_xen_parse_note(struct elf_binary *elf,
             return -1;
         break;
 
+    case XEN_ELFNOTE_SUPPORTED_FEATURES:
+        for ( i = 0; i < XENFEAT_NR_SUBMAPS; ++i )
+            parms->f_supported[i] |= elf_note_numeric_array(
+                elf, note, sizeof(*parms->f_supported), i);
+        break;
+
     }
     return 0;
 }
index 885d5e8ad3293c9eb77643fe4133e26062a9943c..cb97908138920a91e346d1ff83dfe5825768046e 100644 (file)
@@ -227,6 +227,27 @@ uint64_t elf_note_numeric(struct elf_binary *elf, const elf_note * note)
         return 0;
     }
 }
+
+uint64_t elf_note_numeric_array(struct elf_binary *elf, const elf_note *note,
+                                unsigned int unitsz, unsigned int idx)
+{
+    const void *desc = elf_note_desc(elf, note);
+    int descsz = elf_uval(elf, note, descsz);
+
+    if ( descsz % unitsz || idx >= descsz / unitsz )
+        return 0;
+    switch (unitsz)
+    {
+    case 1:
+    case 2:
+    case 4:
+    case 8:
+        return elf_access_unsigned(elf, desc, idx * unitsz, unitsz);
+    default:
+        return 0;
+    }
+}
+
 const elf_note *elf_note_next(struct elf_binary *elf, const elf_note * note)
 {
     int namesz = (elf_uval(elf, note, namesz) + 3) & ~3;
index 2159c04907b093e93b41f3adb651f7d2afe5779f..42d76da87723a611e41bb64a60e6d25d83942484 100644 (file)
  */
 #define XEN_ELFNOTE_MOD_START_PFN 16
 
+/*
+ * The features supported by this kernel (numeric).
+ *
+ * Other than XEN_ELFNOTE_FEATURES on pre-4.2 Xen, this note allows a
+ * kernel to specify support for features that older hypervisors don't
+ * know about. The set of features 4.2 and newer hypervisors will
+ * consider supported by the kernel is the combination of the sets
+ * specified through this and the string note.
+ *
+ * LEGACY: FEATURES
+ */
+#define XEN_ELFNOTE_SUPPORTED_FEATURES 17
+
 /*
  * The number of the highest elfnote defined.
  */
-#define XEN_ELFNOTE_MAX XEN_ELFNOTE_MOD_START_PFN
+#define XEN_ELFNOTE_MAX XEN_ELFNOTE_SUPPORTED_FEATURES
 
 /*
  * System information exported through crash notes.
index 0e3c48624932cf3fcc888cbd06744021fb3a49a8..b4533ccc0bde6f5d6897672e9999b6da856a006e 100644 (file)
 #define XENFEAT_hvm_safe_pvclock           9
 
 /* x86: pirq can be used by HVM guests */
-#define XENFEAT_hvm_pirqs           10
+#define XENFEAT_hvm_pirqs                 10
+
+/* operation as Dom0 is supported */
+#define XENFEAT_dom0                      11
 
 #define XENFEAT_NR_SUBMAPS 1
 
index 584d8b3b2dc551e9df0a7b77d230a923058fc069..9de84eb26787b0daf2340137a940581b320232b1 100644 (file)
@@ -179,6 +179,8 @@ const elf_sym *elf_sym_by_index(struct elf_binary *elf, int index);
 const char *elf_note_name(struct elf_binary *elf, const elf_note * note);
 const void *elf_note_desc(struct elf_binary *elf, const elf_note * note);
 uint64_t elf_note_numeric(struct elf_binary *elf, const elf_note * note);
+uint64_t elf_note_numeric_array(struct elf_binary *, const elf_note *,
+                                unsigned int unitsz, unsigned int idx);
 const elf_note *elf_note_next(struct elf_binary *elf, const elf_note * note);
 
 int elf_is_elfbinary(const void *image);